﻿using System;
using System.Collections.Generic;

using zijian666.Abstractions;
using zijian666.Convertor.Base;
using zijian666.Core;
using zijian666.ConvertExtensions;

namespace zijian666.Convertor;

/// <summary>
/// 数组转换器
/// </summary>
/// <typeparam name="T">数组的元素类型</typeparam>
public class ArrayConvertor<T> : AllowNullConvertor<T?[]?>, IFrom<string, T?[]?>, IFrom<object, T?[]?>, IFrom<object[], T?[]?>
{
    /// <summary>
    /// 从 字符串 <seealso cref="string"/> 转为 <typeparamref name="T"/> 数组
    /// </summary>
    public ConvertResult<T?[]?> From(IConvertContext context, string input)
    {
        if (context is null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        if (string.IsNullOrEmpty(input))
        {
            return new(ArrayHelper<T>.ENPTY);
        }

        var arr = context.Settings.Split(input);
        if (arr is T[] result)
        {
            return new(result);
        }
        return From(context, (object)arr);
    }

    /// <summary>
    /// 从任意对象 <seealso cref="object"/> 转为 <typeparamref name="T"/> 数组
    /// </summary>
    /// <param name="context"></param>
    /// <param name="input"></param>
    /// <returns></returns>
    public ConvertResult<T?[]?> From(IConvertContext context, object input)
    {
        if (context is null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        if (input is null)
        {
            throw new ArgumentNullException(nameof(input));
        }

        var enumerator = new KeyValueEnumerator<object, T>(context, input);

        // input无法循环
        if (enumerator.NotEnumerator)
        {
            var result = context.Convert<T>(input);
            if (result.Success)
            {
                return new([result.Value]);
            }
            return context.ConvertFail(this, input);
        }

        if (enumerator.DynamicCount)
        {
            // 个数不确定
            var list = new List<T?>();
            while (enumerator.MoveNext())
            {
                var result = enumerator.GetValue();
                if (!result.Success)
                {
                    return ExceptionHelper.CollectionAddFail(TypeFriendlyName, list.Count + "", enumerator.OriginalValue, context.Settings.CultureInfo, result.Exception);
                }
                list.Add(result.Value);
            }
            return new([.. list]);
        }

        // input 可循环0次
        if (enumerator.Count == 0)
        {
            return new(ArrayHelper<T>.ENPTY);
        }

        var arr = new T?[enumerator.Count];
        var i = 0;
        while (enumerator.MoveNext())
        {
            var result = enumerator.GetValue();
            if (!result.Success)
            {
                return ExceptionHelper.CollectionAddFail(TypeFriendlyName, i + "", enumerator.OriginalValue, context.Settings.CultureInfo, result.Exception);
            }
            arr[i] = result.Value;
            i++;
        }
        return new(arr);
    }

    /// <inheritdoc />
    public ConvertResult<T?[]?> From(IConvertContext context, object[] input)
    {
        if (context is null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        if (input is null)
        {
            throw new ArgumentNullException(nameof(input));
        }

        return From(context, (object)input);
    }
}
